from backend.database import db
from backend.models.script import Script
import logging
import os
import uuid
import shutil

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('script_manager')

class ScriptManager:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(ScriptManager, cls).__new__(cls)
            # 创建脚本存储目录
            cls._instance.script_storage_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'scripts')
            os.makedirs(cls._instance.script_storage_path, exist_ok=True)
        return cls._instance
    
    def create_script(self, name, description, content, language='python', created_by='system', is_public=False):
        """创建新脚本"""
        try:
            # 检查脚本名称是否已存在
            existing_script = Script.query.filter_by(name=name).first()
            if existing_script:
                # 增加版本号
                new_version = existing_script.version + 1
                new_name = f"{name}_v{new_version}"
                logger.info(f"脚本名称已存在，创建新版本: {new_name}")
            else:
                new_name = name
                new_version = 1
            
            # 创建脚本记录
            new_script = Script(
                name=new_name,
                description=description,
                content=content,
                language=language,
                created_by=created_by,
                is_public=is_public,
                version=new_version
            )
            db.session.add(new_script)
            db.session.commit()
            
            # 保存脚本文件
            self._save_script_file(new_script)
            
            logger.info(f"脚本已创建: {new_name} (ID: {new_script.id})")
            return new_script
        except Exception as e:
            db.session.rollback()
            logger.error(f"创建脚本时发生错误: {str(e)}")
            return None
    
    def get_script_by_id(self, script_id):
        """通过ID获取脚本"""
        try:
            return Script.query.get(script_id)
        except Exception as e:
            logger.error(f"获取脚本时发生错误: {str(e)}")
            return None
    
    def get_all_scripts(self, created_by=None, is_public=False):
        """获取所有脚本"""
        try:
            query = Script.query
            if created_by:
                # 获取用户创建的脚本和公共脚本
                query = query.filter((Script.created_by == created_by) | (Script.is_public == True))
            elif is_public:
                # 只获取公共脚本
                query = query.filter(Script.is_public == True)
            return query.order_by(Script.updated_at.desc()).all()
        except Exception as e:
            logger.error(f"获取脚本列表时发生错误: {str(e)}")
            return []
    
    def update_script(self, script_id, name=None, description=None, content=None, language=None, is_public=None):
        """更新脚本"""
        try:
            script = Script.query.get(script_id)
            if not script:
                logger.warning(f"脚本不存在: {script_id}")
                return None
            
            # 更新脚本信息
            if name is not None:
                script.name = name
            if description is not None:
                script.description = description
            if content is not None:
                script.content = content
            if language is not None:
                script.language = language
            if is_public is not None:
                script.is_public = is_public
            
            db.session.commit()
            
            # 更新脚本文件
            self._save_script_file(script)
            
            logger.info(f"脚本已更新: {script.name} (ID: {script.id})")
            return script
        except Exception as e:
            db.session.rollback()
            logger.error(f"更新脚本时发生错误: {str(e)}")
            return None
    
    def delete_script(self, script_id):
        """删除脚本"""
        try:
            script = Script.query.get(script_id)
            if not script:
                logger.warning(f"脚本不存在: {script_id}")
                return False
            
            # 删除脚本文件
            self._delete_script_file(script)
            
            # 删除数据库记录
            db.session.delete(script)
            db.session.commit()
            
            logger.info(f"脚本已删除: {script.name} (ID: {script.id})")
            return True
        except Exception as e:
            db.session.rollback()
            logger.error(f"删除脚本时发生错误: {str(e)}")
            return False
    
    def upload_script(self, file, description=None, language='python', created_by='system', is_public=False):
        """上传脚本文件"""
        try:
            # 读取文件内容
            content = file.read().decode('utf-8')
            
            # 获取文件名（不含扩展名）
            filename = os.path.splitext(file.filename)[0]
            
            # 检测文件语言
            file_ext = os.path.splitext(file.filename)[1].lower()
            if file_ext == '.py':
                language = 'python'
            elif file_ext in ['.sh', '.bash']:
                language = 'shell'
            elif file_ext == '.java':
                language = 'java'
            
            # 创建脚本
            return self.create_script(
                name=filename,
                description=description or f"上传的{language}脚本",
                content=content,
                language=language,
                created_by=created_by,
                is_public=is_public
            )
        except Exception as e:
            logger.error(f"上传脚本时发生错误: {str(e)}")
            return None
    
    def _save_script_file(self, script):
        """保存脚本文件"""
        try:
            # 创建用户目录
            user_dir = os.path.join(self.script_storage_path, script.created_by)
            os.makedirs(user_dir, exist_ok=True)
            
            # 生成唯一的文件名
            file_ext = self._get_file_extension(script.language)
            filename = f"{script.id}_{script.name}{file_ext}"
            filepath = os.path.join(user_dir, filename)
            
            # 写入文件
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(script.content)
            
            logger.debug(f"脚本文件已保存: {filepath}")
        except Exception as e:
            logger.error(f"保存脚本文件时发生错误: {str(e)}")
    
    def _delete_script_file(self, script):
        """删除脚本文件"""
        try:
            # 获取文件路径
            user_dir = os.path.join(self.script_storage_path, script.created_by)
            file_ext = self._get_file_extension(script.language)
            filename = f"{script.id}_{script.name}{file_ext}"
            filepath = os.path.join(user_dir, filename)
            
            # 删除文件
            if os.path.exists(filepath):
                os.remove(filepath)
                logger.debug(f"脚本文件已删除: {filepath}")
            
            # 如果用户目录为空，删除目录
            if os.path.exists(user_dir) and not os.listdir(user_dir):
                os.rmdir(user_dir)
        except Exception as e:
            logger.error(f"删除脚本文件时发生错误: {str(e)}")
    
    def _get_file_extension(self, language):
        """根据语言获取文件扩展名"""
        extensions = {
            'python': '.py',
            'shell': '.sh',
            'java': '.java',
            'javascript': '.js',
            'kotlin': '.kt',
            'c': '.c',
            'cpp': '.cpp',
            'csharp': '.cs',
            'php': '.php',
            'ruby': '.rb',
            'go': '.go'
        }
        return extensions.get(language.lower(), '.txt')
    
    def search_scripts(self, keyword):
        """搜索脚本"""
        try:
            # 在名称和描述中搜索关键词
            query = Script.query.filter(
                (Script.name.like(f'%{keyword}%')) | 
                (Script.description.like(f'%{keyword}%'))
            )
            return query.all()
        except Exception as e:
            logger.error(f"搜索脚本时发生错误: {str(e)}")